package com.uh.rds.testing.validator;

import com.uh.rds.testing.base.DataValidator;
import com.uh.rds.testing.base.DataValidatorStep;
import com.uh.rds.testing.conn.Endpoint;
import com.uh.rds.testing.logger.TestLoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.stream.Collectors;

import static com.uh.rds.testing.TestingConstants.MAX_EXPIRE_SECONDS;
import static com.uh.rds.testing.base.DataValidatorStep.*;

public class DataValidatorThread implements Runnable {
    private Logger logger = TestLoggerFactory.getLogger(this.getClass());
    private int index; //显示信息时做区分
    private Endpoint endpoint; //做操作时的连接地址
    private Endpoint slaveEndpoint;//做验证时的连接地址
    private List<DataValidator> dataValidators = new ArrayList<>();

    private DataValidatorArguments arguments;

    private boolean doValidate;
    private boolean doProcess;
    private boolean doExpire;
    private boolean doValidateExpired;
    private boolean doClear;

    public DataValidatorThread(int index, Endpoint endpoint, Endpoint slaveEndpoint, DataValidatorArguments arguments) {
        this.index = index;
        this.endpoint = endpoint;
        this.slaveEndpoint = slaveEndpoint;
        this.arguments = arguments;
    }

    public int getIndex() {
        return index;
    }

    public void addValidator(DataValidator validator) {
        this.dataValidators.add(validator);
    }

    public List<DataValidator> getDataValidators() {
        return dataValidators;
    }

    public void setSteps(DataValidatorStep... steps) {
        Set<DataValidatorStep> stepsSet = Arrays.stream(steps).collect(Collectors.toSet());

        this.doValidate = stepsSet.contains(VALIDATE);
        this.doProcess = stepsSet.contains(PROCESS);
        this.doExpire = stepsSet.contains(EXPIRE);
        this.doValidateExpired = stepsSet.contains(VALIDATE_EXPIRED);
        this.doClear = stepsSet.contains(CLEAR);
    }


    @Override
    public void run() {
        Jedis jedis = null;
        Jedis validateJedis = null;

        validateConfig();

        try {
            logger.info("[Thread" + index + "] starts to run testing!");

            jedis = endpoint.newJedis();
            if(doValidate || doValidateExpired) {
                if(arguments.validateFromSlave) {
                    if(slaveEndpoint == null) {
                        throw new RuntimeException("Slave endpoint is null!");
                    }
                    validateJedis = slaveEndpoint.newJedis();
                }
                else {
                    validateJedis = jedis;
                }
            }



            List<DataValidator> reorderedDataValidators  =  new ArrayList<>(dataValidators);
            if(arguments.randomOrder) {
                Collections.shuffle(reorderedDataValidators);
            }

            //做数据处理和验证
            for(DataValidator validator : reorderedDataValidators) {
                validator.setRuntime(jedis, validateJedis);
                if(doProcess) {
                    //数据进行处理
                    try {
                        validator.process();
                    } catch (Exception e) {
                        logger.error("{} Validator process is error!", validator.getName(), e);
                    }
                }

                if(doExpire) {
                    //设置过期时间
                    try {
                        long expireCount = validator.expire(arguments.expireSeconds);
                        logger.info("{} Validator set expired data count:{}", validator.getName(), expireCount);
                    } catch (Exception e) {
                        logger.error("{} Validator expire is error!", validator.getName(), e);
                    }
                }


                if(doValidateExpired) { //如果设置了过期时间，验证过期
                    if(doProcess) {
                        Thread.sleep((arguments.expireSeconds + 1) * 1000L); //等待到（过期时间+1秒）后再验证
                    }

                    validator.validateExpired(); //验证所有的Key是否都不存在
                }


                if(doValidate) {
                    //数据进行验证
                    try {
                        if(doProcess) {
                            try { Thread.sleep(arguments.validateInterval); } catch (InterruptedException e) { throw new RuntimeException(e); }
                        }

                        validator.validate();
                    }
                    catch (Exception e) {
                        logger.error("{} Validator validate is error!", validator.getName(), e);
                    }
                }
            }

            if(doClear) {
                //做数据清理
                for(DataValidator validator : reorderedDataValidators) {
                    try {
                        validator.clear();
                    }
                    catch (Exception e) {
                        logger.error("{} Validator clear is error!", validator.getName(), e);
                    }
                }
            }
        }
        catch (Exception e) {
            logger.error("[Thread{}] Validator is error!", index, e);
        }
        finally {
            if(jedis != null && jedis.isConnected()) {
                jedis.close();
            }
            if(validateJedis != null && validateJedis.isConnected()) {
                validateJedis.close();
            }
        }

        logger.info("[Thread{}] Validator is end!", index);
    }

    /**
     * 验证配置是否正确
     */
    private void validateConfig() {
        if(dataValidators.isEmpty()) {
            throw new RuntimeException("DataValidators is empty!");
        }

        if(doValidate && arguments.validateFromSlave && slaveEndpoint == null) {
            throw new RuntimeException("Slave endpoint is null!");
        }

        if(doExpire && (arguments.expireSeconds < 2 || arguments.expireSeconds > MAX_EXPIRE_SECONDS)) {
            throw new RuntimeException("Expire seconds is invalid! It must be in (2, " + MAX_EXPIRE_SECONDS + ")");
        }
    }

}



